/**
 * 各种扩展属性类，用于简化代码
 */
module cl {

    export class TroopEx extends Troop {
        public constructor(
            public name : string, // 部队番号
            public force : number, // 所属：[0]势力
            public troop_type : number, // 部队类型
            public aliasname : string, // 外号
            public emplace_time : number[], // 进入战场时间（用于增援部队）
            public tile : Tile,
            public orientation : number,
            public level : number, // 战力效率（王牌，精英等部队有加成，预备役部队有衰益）
            public morale : number, // 士气效率
            public strength : number, // 有生力量，一般整备师81，整备旅27，整备团9，整备营3，整备连1
            public ammo : number, // 当前弹药基数（可连续战斗5天）
            public fuel : number, // 当前燃油基数（可连续战斗10天）
            public radio_silence : boolean, // 处于无线电静默状态，不会被雷达，电子侦察机发现
            public move_remain : number // 剩余移动力，当需要移动受堵塞时，则可累积移动力。当被牵制被击溃时，负数用于记录恢复时间
        ){
            super(name, force, troop_type, aliasname, emplace_time, tile, orientation, level, morale, strength, ammo, fuel, radio_silence, move_remain);
        }

        public tid : number;
        public coord : Coord;

        public type_name : string;
        public base_image : string; // 标志图标
        public standby_effect : string; // 待命音效
        public plane : number; // 位面 -1:天堂(已死或重组) 0:场内 1:场外
        public man_strength : number; // 每1点strength有多少人
        public attack_efficiency : number[]; // 对不同troop_type的攻击力，同时用于标识不可攻击目标
        public attack_range : number; // 攻击距离，即可以间隔多少个网格外攻击，地面部队除火炮部队外均为1;
        public attack_range_decline : number; // 每间隔1格损失0点攻击力，用例如：榴弹炮攻击距离远则精度下降（预留备用）
        public ammo_limit : number; // 满载弹药基数（可连续战斗5天）
        public move_ability : boolean[]; // 各land_type的可行性，详见 zone.land_type_def
        public move : number; // 移动速度（每天移动32）
        public fuel_limit : number; // 满载燃油基数（可连续行驶10天）
        public detect_range : number; // 侦查半径（预留备用）
        public conceal_range : number; // 隐藏半径（预留备用）
        public priority : number; // 被攻击时的优先级

        public force_name : string;
        public color : number[];
        public flag : string;
        public force_tile : Tile;
        public force_hostile_index : number[]; // 敌对指数：控制[1]方城市时，该城市对己方的补给容量降低35%，同时用于标识同盟势力和敌对势力
        public force_map : ForceMap;

        public refreshLocation() : void {
            this.tid = Map.tileEngine.tile2tid(this.tile);
            this.coord = Map.tileEngine.tile2coord(this.tile);
        }

        public init() : void {
            this.refreshLocation();

            let troop_type = Campaign.troop_type[this.troop_type];
            this.type_name = troop_type.name;
            this.base_image = troop_type.base_image;
            this.standby_effect = troop_type.standby_effect;
            this.plane = this.strength <= 0 ? -1 : troop_type.plane;
            this.man_strength = troop_type.man_strength;
            this.attack_efficiency = troop_type.attack_efficiency;
            this.attack_range = troop_type.attack_range;
            this.attack_range_decline = troop_type.attack_range_decline;
            this.ammo_limit = troop_type.ammo_limit;
            this.move_ability = troop_type.move_ability;
            this.move = troop_type.move;
            this.fuel_limit = troop_type.fuel_limit;
            this.detect_range = troop_type.detect_range;
            this.conceal_range = troop_type.conceal_range;
            this.priority = troop_type.priority;

            let force = Campaign.force[this.force];
            this.force_name = force.name;
            this.color = force.color;
            this.flag = force.flag;
            this.force_tile = force.tile;
            this.force_hostile_index = force.force_hostile_index;
            this.force_map = force.force_map;
        }
    }

    export class ForceEx extends Force {
        public constructor(
            public name : string,
            public description : string,
            public color : number[],
            public flag : string,
            public tile : Tile,
            public force_hostile_index : number[], // 敌对指数：控制[1]方城市时，该城市对己方的补给容量降低35%，同时用于标识同盟势力和敌对势力
            public force_map : ForceMap
        ){
            super(name, description, color, flag, tile, force_hostile_index, force_map);
        }

        public tid : number;
        public coord : Coord;
        public innerTroop : number[];
        public courtTroop : number[];

        public init(id : number) : void {
            this.tid = Map.tileEngine.tile2tid(this.tile);
            this.coord = Map.tileEngine.tile2coord(this.tile);

            this.innerTroop = [];
            this.courtTroop = [];

            for (let i = 0; i < Campaign.troop.length; i++) {
                if (Campaign.troop[i].force == id) {
                    if (Campaign.troop[i].plane == 0) {
                        this.innerTroop.push(i);
                    } else if (Campaign.troop[i].plane == 1) {
                        this.courtTroop.push(i);
                    }
                }
            }
        }
    }

    export class TroopTypeEx extends TroopType {
        public constructor(
            public name : string,
            public base_image : string, // 标志图标
            public standby_effect : string, // 待命音效
            public plane : number, // 位面 -1:天堂(已死或重组) 0:场内 1:场外
            public man_strength : number, // 每1点strength有多少人
            public attack_efficiency : number[], // 对不同troop_type的攻击力，同时用于标识不可攻击目标
            public attack_range : number, // 攻击距离，即可以间隔多少个网格外攻击，地面部队除火炮部队外均为1,
            public attack_range_decline : number, // 每间隔1格损失0点攻击力，用例如：榴弹炮攻击距离远则精度下降（预留备用）
            public ammo_limit : number, // 满载弹药基数（可连续战斗5天）
            public move_ability : boolean[], // 各land_type的可行性，详见 zone.land_type_def
            public move : number, // 移动速度（每天移动32）
            public fuel_limit : number, // 满载燃油基数（可连续行驶10天）
            public detect_range : number, // 侦查半径（预留备用）
            public conceal_range : number, // 隐藏半径（预留备用）
            public priority : number // 被攻击时的优先级
        ){
            super(name, base_image, standby_effect, plane, man_strength, attack_efficiency, attack_range, attack_range_decline, 
                    ammo_limit, move_ability, move, fuel_limit, detect_range, conceal_range, priority);
        }

        public troop : number[];

        public init(id : number) : void {
            this.troop = [];

            for (let i = 0; i < Campaign.troop.length; i++) {
                if (Campaign.troop[i].troop_type == id && Campaign.troop[i].plane >= 0) {
                    this.troop.push(i);
                }
            }
        }
    }

    export class CampaignDataEx {
        public constructor(
            data : CampaignData,
        ){
            this.filename = data.filename;
            this.filetype = data.filetype;
            this.version = data.version;
            this.title = data.title;
            this.description = data.description;

            let time_ref = data.time_ref;
            this.time_ref = new TimeReference(
                time_ref.time.concat(),
                time_ref.current_step,
                time_ref.force_of_step,
                time_ref.game_speed,
                time_ref.time_of_step,
                time_ref.ticks_of_step
            );

            this.force = [];
            for (let forceid = 0; forceid < data.force.length; forceid++) {
                let force = data.force[forceid];
                this.force.push(new ForceEx(
                    force.name,
                    force.description,
                    force.color,
                    force.flag,
                    new Tile(force.tile.x, force.tile.y),
                    force.force_hostile_index.concat(),
                    JSON.parse(JSON.stringify(force.force_map)) as ForceMap));
            }

            this.troop_type = [];
            for (let typeid = 0; typeid < data.troop_type.length; typeid++) {
                let troop_type = data.troop_type[typeid];
                this.troop_type.push(new TroopTypeEx(
                    troop_type.name,
                    troop_type.base_image,
                    troop_type.standby_effect,
                    troop_type.plane,
                    troop_type.man_strength,
                    troop_type.attack_efficiency.concat(),
                    troop_type.attack_range,
                    troop_type.attack_range_decline,
                    troop_type.ammo_limit,
                    troop_type.move_ability.concat(),
                    troop_type.move,
                    troop_type.fuel_limit,
                    troop_type.detect_range,
                    troop_type.conceal_range,
                    troop_type.priority));
            }

            this.troop = [];
            for (let troopid = 0; troopid < data.troop.length; troopid++) {
                let troop = data.troop[troopid];
                this.troop.push(new TroopEx(
                    troop.name,
                    troop.force,
                    troop.troop_type,
                    troop.aliasname,
                    troop.emplace_time.concat(),
                    new Tile(troop.tile.x, troop.tile.y),
                    troop.orientation,
                    troop.level,
                    troop.morale,
                    troop.strength,
                    troop.ammo,
                    troop.fuel,
                    troop.radio_silence,
                    troop.move_remain));
            }

            let zone = data.zone;
            this.zone = new Zone(
                zone.site,
                zone.landforms,
                zone.center_latlng.concat(),
                zone.scale,
                zone.tile_area,
                zone.xsize,
                zone.ysize,
                zone.base_image,
                zone.real_image,
                zone.mini_image,
                zone.land_type_def.concat(),
                zone.land_type_default,
                zone.land_type.concat(),
                zone.defend_index,
                zone.pass_index.concat(),
                JSON.parse(JSON.stringify(zone.highway_pointpair)) as ZoneTilePair[],
                JSON.parse(JSON.stringify(zone.expressway_pointpair)) as ZoneTilePair[],
                JSON.parse(JSON.stringify(zone.railway_pointpair)) as ZoneTilePair[],
                JSON.parse(JSON.stringify(zone.recharge_point)) as ZoneRecharge[],
                JSON.parse(JSON.stringify(zone.label_point)) as ZoneLabel[],
                JSON.parse(JSON.stringify(zone.win_point)) as ZoneWinPoint[]
            );
        }

        public filename : string;
        public filetype : string;
        public version : string;
        public title : string;
        public description : string;
        public time_ref : TimeReference;
        public force : ForceEx[];
        public troop_type : TroopTypeEx[];
        public troop : TroopEx[];
        public zone : Zone;

        public init() : void {
            // troop_type's priority
            for (let i = 0; i < this.troop_type.length; i++){
                let attack = 0;
                let beAttack = 0;
                for (let j = 0; j < this.troop_type.length; j++){
                    attack += this.troop_type[i].attack_efficiency[j];
                    beAttack += this.troop_type[j].attack_efficiency[i];
                }
                let rate = attack / beAttack;
                this.troop_type[i].priority = rate;
            }

            for (let i = 0; i < this.troop.length; i++){
                this.troop[i].init();
            }
            for (let i = 0; i < this.force.length; i++){
                this.force[i].init(i);
            }
            for (let i = 0; i < this.troop_type.length; i++){
                this.troop_type[i].init(i);
            }
        }

        public toPrimitive() : CampaignData {
            return new CampaignData(
                this.filename,
                this.filetype,
                this.version,
                this.title,
                this.description,
                this.time_ref,
                this.force,
                this.troop_type,
                this.troop,
                this.zone
            )
        }
    }
}